home *** CD-ROM | disk | FTP | other *** search
/ PC Media 2 / PC MEDIA CD02.iso / share / prog / iterm / async.inc next >
Encoding:
Text File  |  1986-01-24  |  15.8 KB  |  402 lines

  1. === Qmodem Capture File ===
  2. Enter choice: 4
  3.  
  4. Capture Buffer Transfer
  5.  
  6. No error detection/correction
  7.  
  8.  
  9.  
  10. Opening capture buffer...
  11.  
  12. {----------------------------------------------------------------------}
  13.  
  14. {                                                                      } 
  15.  
  16. {                          ASYNC.INC                                   } 
  17.  
  18. {                                                                      } 
  19.  
  20. {  Async Communication Routines                                        } 
  21.  
  22. {  by Michael Quinlan                                                  } 
  23.  
  24. {  with a bug fixed by Scott Herr                                      }
  25.  
  26. {  made PCjr-compatible by W. M. Miller                                }
  27.  
  28. {  Highly dependant on the IBM PC and PC DOS 2.0                       } 
  29.  
  30. {                                                                      } 
  31.  
  32. {  based on the DUMBTERM program by CJ Dunford in the January 1984     } 
  33.  
  34. {  issue of PC Tech Journal.                                           } 
  35.  
  36. {                                                                      } 
  37.  
  38. {  Entry points:                                                       } 
  39.  
  40. {                                                                      } 
  41.  
  42. {    Async_Init                                                        } 
  43.  
  44. {      Performs initialization.                                        }
  45.  
  46. {                                                                      } 
  47.  
  48. {    Async_Open(Port, Baud : Integer;                                  } 
  49.  
  50. {               Parity : Char;                                         } 
  51.  
  52. {               WordSize, StpBits : Integer) : Boolean                 } 
  53.  
  54. {      Sets up interrupt vector, initialies the COM port for           } 
  55.  
  56. {      processing, sets pointers to the buffer.  Returns FALSE if COM  } 
  57.  
  58. {      port not installed.                                             } 
  59.  
  60. {                                                                      }
  61.  
  62. {    Async_Buffer_Check(var C : Char) : Boolean                        }
  63.  
  64. {      If a character is available, returns TRUE and moves the         }
  65.  
  66. {        character from the buffer to the parameter                    }
  67.  
  68. {      Otherwise, returns FALSE                                        }
  69.  
  70. {                                                                      }
  71.  
  72. {    Async_Send(C : Char)                                              }
  73.  
  74. {      Transmits the character.                                        }
  75.  
  76. {                                                                      }
  77.  
  78. {    Async_Send_String(S : LStr)                                       }
  79.  
  80. {      Calls Async_Send to send each character of S.                   }
  81.  
  82. {                                                                      }
  83.  
  84. {    Async_Close                                                       }
  85.  
  86. {      Turn off the COM port interrupts.                               }
  87.  
  88. {      **MUST** BE CALLED BEFORE EXITING YOUR PROGRAM; otherwise you   }
  89.  
  90. {      will see some really strange errors and have to re-boot.        }
  91.  
  92. {                                                                      }
  93.  
  94. {----------------------------------------------------------------------}
  95.  
  96.  
  97.  
  98. { global declarations }
  99.  
  100.  
  101.  
  102. type
  103.  
  104.   LStr = String[255];  { generic string type for parameters }
  105.  
  106.  
  107.  
  108. const
  109.  
  110.   UART_THR = $00;    { offset from base of UART Registers for IBM PC } 
  111.  
  112.   UART_RBR = $00; 
  113.  
  114.   UART_IER = $01; 
  115.  
  116.   UART_IIR = $02; 
  117.  
  118.   UART_LCR = $03; 
  119.  
  120.   UART_MCR = $04; 
  121.  
  122.   UART_LSR = $05; 
  123.  
  124.   UART_MSR = $06; 
  125.  
  126.  
  127.  
  128.   I8088_IMR = $21;   { port address of the Interrupt Mask Register } 
  129.  
  130.  
  131.  
  132. const 
  133.  
  134.   Async_DSeg_Save : Integer = 0;  { Save DS reg in Code Segment for interrupt 
  135.  
  136.                                     routine } 
  137.  
  138.  
  139.  
  140. const
  141.  
  142.   Async_Buffer_Max = 4095;
  143.  
  144.  
  145.  
  146. var 
  147.  
  148.   Async_Buffer       : Array[0..Async_Buffer_Max] of char; 
  149.  
  150.  
  151.  
  152.   Async_Open_Flag    : Boolean;   { true if Open but no Close } 
  153.  
  154.   Async_Port         : Integer;   { current Open port number (1 or 2) } 
  155.  
  156.   Async_Base         : Integer;   { base for current open port } 
  157.  
  158.   Async_Irq          : Integer;   { irq for current open port } 
  159.  
  160.  
  161.  
  162.   Async_Buffer_Overflow : Boolean;  { True if buffer overflow has happened } 
  163.  
  164.   Async_Buffer_Used     : Integer; 
  165.  
  166.   Async_MaxBufferUsed   : Integer; 
  167.  
  168.  
  169.  
  170.     { Async_Buffer is empty if Head = Tail } 
  171.  
  172.   Async_Buffer_Head  : Integer;   { Locn in Async_Buffer to put next char } 
  173.  
  174.   Async_Buffer_Tail  : Integer;   { Locn in Async_Buffer to get next char } 
  175.  
  176.   Async_Buffer_NewTail : Integer;
  177.  
  178.  
  179.  
  180.   Async_BIOS_Port_Table : Array[1..2] of Integer absolute $40:0;
  181.  
  182.                { This table is initialized by BIOS equipment determination
  183.  
  184.                  code at boot time to contain the base addresses for the
  185.  
  186.                  installed async adapters.  A value of 0 means "not in-
  187.  
  188.                  stalled." }
  189.  
  190.  
  191.  
  192. const 
  193.  
  194.   Async_Num_Bauds = 8; 
  195.  
  196.   Async_Baud_Table : array [1..Async_Num_Bauds] of record 
  197.  
  198.                                                      Baud, Bits : integer
  199.  
  200.                                                    end
  201.  
  202.                    = ((Baud:110;  Bits:$00), 
  203.  
  204.                       (Baud:150;  Bits:$20), 
  205.  
  206.                       (Baud:300;  Bits:$40), 
  207.  
  208.                       (Baud:600;  Bits:$60), 
  209.  
  210.                       (Baud:1200; Bits:$80), 
  211.  
  212.                       (Baud:2400; Bits:$A0), 
  213.  
  214.                       (Baud:4800; Bits:$C0), 
  215.  
  216.                       (Baud:9600; Bits:$E0)); 
  217.  
  218.  
  219.  
  220.  
  221.  
  222. procedure BIOS_RS232_Init(ComPort, ComParm : Integer); 
  223.  
  224. { Issue Interrupt $14 to initialize the UART } 
  225.  
  226. { See the IBM PC Technical Reference Manual for the format of ComParm } 
  227.  
  228. var 
  229.  
  230.   Regs : record 
  231.  
  232.            ax, bx, cx, dx, bp, si, di, ds, es, flag : Integer 
  233.  
  234.          end; 
  235.  
  236. begin 
  237.  
  238.   with Regs do 
  239.  
  240.     begin 
  241.  
  242.       ax := ComParm and $00FF;  { AH=0; AL=ComParm } 
  243.  
  244.       dx := ComPort;
  245.  
  246.       Intr($14, Regs)
  247.  
  248.     end 
  249.  
  250. end; { BIOS_RS232_Init } 
  251.  
  252.  
  253.  
  254. procedure DOS_Set_Intrpt(v, s, o : integer); 
  255.  
  256. { call DOS to set an interrupt vector } 
  257.  
  258. var 
  259.  
  260.   Regs : Record 
  261.  
  262.            ax, bx, cx, dx, bp, si, di, ds, es, flag : integer 
  263.  
  264.          end; 
  265.  
  266. begin 
  267.  
  268.   with Regs do 
  269.  
  270.     begin 
  271.  
  272.       ax := $2500 + (v and $00FF); 
  273.  
  274.       ds := s; 
  275.  
  276.       dx := o; 
  277.  
  278.       MsDos(Regs) 
  279.  
  280.     end 
  281.  
  282. end; { DOS_Set_Intrpt } 
  283.  
  284.  
  285.  
  286. {----------------------------------------------------------------------} 
  287.  
  288. {                                                                      } 
  289.  
  290. {  ASYNCISR.INC - Interrupt Service Routine                            }
  291.  
  292. {                                                                      }
  293.  
  294. {----------------------------------------------------------------------} 
  295.  
  296.  
  297.  
  298. procedure Async_Isr; 
  299.  
  300. { Interrupt Service Routine } 
  301.  
  302. { Invoked when the UART has received a byte of data from the 
  303.  
  304.   communication line } 
  305.  
  306.  
  307.  
  308. { re-written 9/10/84 to be entirely in machine language; original source 
  309.  
  310.   left as comments } 
  311.  
  312.  
  313.  
  314. begin 
  315.  
  316.  
  317.  
  318.   {NOTE: on entry, Turbo Pascal has already PUSHed BP and SP } 
  319.  
  320.  
  321.  
  322.   Inline( 
  323.  
  324.       { save all registers used } 
  325.  
  326.     $50/                           { PUSH AX } 
  327.  
  328.     $53/                           { PUSH BX } 
  329.  
  330.     $52/                           { PUSH DX } 
  331.  
  332.     $1E/                           { PUSH DS } 
  333.  
  334.     $FB/                           { STI } 
  335.  
  336.       { set up the DS register to point to Turbo Pascal's data segment }
  337.  
  338.     $2E/$FF/$36/Async_Dseg_Save/   { PUSH CS:Async_Dseg_Save }
  339.  
  340.     $1F/                           { POP DS } 
  341.  
  342.       { get the incomming character } 
  343.  
  344.       { Async_Buffer[Async_Buffer_Head] := Chr(Port[UART_RBR + Async_Base]); } 
  345.  
  346.     $8B/$16/Async_Base/            { MOV DX,Async_Base } 
  347.  
  348.     $EC/                           { IN AL,DX } 
  349.  
  350.     $8B/$1E/Async_Buffer_Head/     { MOV BX,Async_Buffer_Head } 
  351.  
  352.     $88/$87/Async_Buffer/          { MOV Async_Buffer[BX],AL } 
  353.  
  354.       { Async_Buffer_NewHead := Async_Buffer_Head + 1; } 
  355.  
  356.     $43/                           { INC BX } 
  357.  
  358.       { if Async_Buffer_NewHead > Async_Buffer_Max then 
  359.  
  360.           Async_Buffer_NewHead := 0; } 
  361.  
  362.     $81/$FB/Async_Buffer_Max/      { CMP BX,Async_Buffer_Max } 
  363.  
  364.     $7E/$02/                       { JLE L001 } 
  365.  
  366.     $33/$DB/                       { XOR BX,BX } 
  367.  
  368.       { if Async_Buffer_NewHead = Async_Buffer_Tail then 
  369.  
  370.           Async_Buffer_Overflow := TRUE 
  371.  
  372.         else } 
  373.  
  374. {L001:} 
  375.  
  376.     $3B/$1E/Async_Buffer_Tail/     { CMP BX,Async_Buffer_Tail } 
  377.  
  378.     $75/$08/                       { JNE L002 } 
  379.  
  380.     $C6/$06/Async_Buffer_Overflow/$01/ { MOV Async_Buffer_Overflow,1 } 
  381.  
  382.     $90/                           { NOP generated by assembler for some reason 
  383.  
  384.  
  385.     $EB/$16/                       { JMP SHORT L003 }
  386.  
  387.       { begin 
  388.  
  389.           Async_Buffer_Head := Async_Buffer_NewHead; 
  390.  
  391.           Async_Buffer_Used := Async_Buffer_Used + 1; 
  392.  
  393.           if Async_Buffer_Used > Async_MaxBufferUsed then 
  394.  
  395.             Async_MaxBufferUsed := Async_Buffer_Used 
  396.  
  397.         end; } 
  398.  
  399. {L002:} 
  400.  
  401.     $89/$1E/Async_Buffer_Head/     { MOV Async_Buffer_Head,BX } 
  402.  
  403.     $FF/$06/Async_Buffer_Used/     { INC Async_Buffer_Used } 
  404.  
  405.     $8B/$1E/Async_Buffer_Used/     { MOV BX,Async_Buffer_Used } 
  406.  
  407.     $3B/$1E/Async_MaxBufferUsed/   { CMP BX,Async_MaxBufferUsed } 
  408.  
  409.     $7E/$04/                       { JLE L003 } 
  410.  
  411.     $89/$1E/Async_MaxBufferUsed/   { MOV Async_MaxBufferUsed,BX } 
  412.  
  413. {L003:} 
  414.  
  415.       { disable interrupts } 
  416.  
  417.     $FA/                           { CLI } 
  418.  
  419.       { Port[$20] := $20; }  { use non-specific EOI } 
  420.  
  421.     $B0/$20/                       { MOV AL,20h } 
  422.  
  423.     $E6/$20/                       { OUT 20h,AL } 
  424.  
  425.       { restore the registers then use IRET to return } 
  426.  
  427.       { the last two POPs are required because Turbo Pascal PUSHes these regs 
  428.  
  429.         before we get control.  The manual doesn't so it, but that is what
  430.  
  431.         really happens }
  432.  
  433.     $1F/                           { POP DS } 
  434.  
  435.     $5A/                           { POP DX } 
  436.  
  437.     $5B/                           { POP BX } 
  438.  
  439.     $58/                           { POP AX } 
  440.  
  441.     $5C/                           { POP SP } 
  442.  
  443.     $5D/                           { POP BP } 
  444.  
  445.     $CF)                           { IRET } 
  446.  
  447. end; { Async_Isr } 
  448.  
  449.  
  450.  
  451. procedure Async_Init; 
  452.  
  453. { initialize variables } 
  454.  
  455. begin 
  456.  
  457.   Async_DSeg_Save := DSeg; 
  458.  
  459.   Async_Open_Flag := FALSE; 
  460.  
  461.   Async_Buffer_Overflow := FALSE; 
  462.  
  463.   Async_Buffer_Used := 0; 
  464.  
  465.   Async_MaxBufferUsed := 0; 
  466.  
  467. end; { Async_Init } 
  468.  
  469.  
  470.  
  471. procedure Async_Close; 
  472.  
  473. { reset the interrupt system when UART interrupts no longer needed } 
  474.  
  475. var
  476.  
  477.   i, m : Integer;
  478.  
  479. begin 
  480.  
  481.   if Async_Open_Flag then 
  482.  
  483.     begin 
  484.  
  485.  
  486.  
  487.       { disable the IRQ on the 8259 } 
  488.  
  489.       Inline($FA);         { disable interrupts } 
  490.  
  491.       i := Port[I8088_IMR];        { get the interrupt mask register } 
  492.  
  493.       m := 1 shl Async_Irq;        { set mask to turn off interrupt } 
  494.  
  495.       Port[I8088_IMR] := i or m; 
  496.  
  497.  
  498.  
  499.       { disable the 8250 data ready interrupt } 
  500.  
  501.       Port[UART_IER + Async_Base] := 0; 
  502.  
  503.  
  504.  
  505.       { disable OUT2 on the 8250 } 
  506.  
  507.       Port[UART_MCR + Async_Base] := 0; 
  508.  
  509.       Inline($FB);          { enable interrupts }
  510.  
  511.  
  512.  
  513.       { re-initialize our data areas so we know the port is closed } 
  514.  
  515.       Async_Open_Flag := FALSE 
  516.  
  517.  
  518.  
  519.     end 
  520.  
  521. end; { Async_Close }
  522.  
  523.  
  524.  
  525. function Async_Open(ComPort       : Integer; 
  526.  
  527.                     BaudRate      : Integer; 
  528.  
  529.                     Parity        : Char; 
  530.  
  531.                     WordSize      : Integer; 
  532.  
  533.                     StopBits      : Integer) : Boolean; 
  534.  
  535. { open a communications port } 
  536.  
  537. var 
  538.  
  539.   ComParm : Integer; 
  540.  
  541.   i, m : Integer; 
  542.  
  543. begin 
  544.  
  545.   if Async_Open_Flag then Async_Close; 
  546.  
  547.  
  548.  
  549.   if (ComPort = 2) and (Async_BIOS_Port_Table[2] <> 0) then
  550.  
  551.     Async_Port := 2
  552.  
  553.   else
  554.  
  555.     Async_Port := 1;  { default to COM1 }
  556.  
  557.   Async_Base := Async_BIOS_Port_Table[Async_Port];
  558.  
  559.   Async_Irq := Hi(Async_Base) + 1;
  560.  
  561.  
  562.  
  563.   if (Port[UART_IIR + Async_Base] and $00F8) <> 0 then 
  564.  
  565.     Async_Open := FALSE 
  566.  
  567.   else
  568.  
  569.     begin 
  570.  
  571.       Async_Buffer_Head := 0; 
  572.  
  573.       Async_Buffer_Tail := 0; 
  574.  
  575.       Async_Buffer_Overflow := FALSE; 
  576.  
  577.  
  578.  
  579.   { Build the ComParm for RS232_Init } 
  580.  
  581.   { See Technical Reference Manual for description } 
  582.  
  583.  
  584.  
  585.       ComParm := $0000; 
  586.  
  587.  
  588.  
  589.   { Set up the bits for the baud rate } 
  590.  
  591.       i := 0; 
  592.  
  593.       repeat 
  594.  
  595.         i := i + 1 
  596.  
  597.       until (Async_Baud_Table[i].Baud = BaudRate) or (i = Async_Num_Bauds); 
  598.  
  599.       ComParm := ComParm or Async_Baud_Table[i].Bits; 
  600.  
  601.  
  602.  
  603.       if Parity in ['E', 'e'] then ComParm := ComParm or $0018
  604.  
  605.       else if Parity in ['O', 'o'] then ComParm := ComParm or $0008 
  606.  
  607.       else ComParm := ComParm or $0000;  { default to No parity } 
  608.  
  609.  
  610.  
  611.       if WordSize = 7 then ComParm := ComParm or $0002 
  612.  
  613.       else ComParm := ComParm or $0003;  { default to 8 data bits }
  614.  
  615.  
  616.  
  617.       if StopBits = 2 then ComParm := ComParm or $0004 
  618.  
  619.       else ComParm := ComParm or $0000;  { default to 1 stop bit } 
  620.  
  621.  
  622.  
  623.   { use the BIOS COM port initialization routine to save typing the code } 
  624.  
  625.       BIOS_RS232_Init(Async_Port - 1, ComParm); 
  626.  
  627.  
  628.  
  629.       DOS_Set_Intrpt(Async_Irq + 8, CSeg, Ofs(Async_Isr)); 
  630.  
  631.  
  632.  
  633.   { read the RBR and reset any possible pending error conditions } 
  634.  
  635.   { first turn off the Divisor Access Latch Bit to allow access to RBR, etc. } 
  636.  
  637.  
  638.  
  639.       Inline($FA);  { disable interrupts } 
  640.  
  641.  
  642.  
  643.       Port[UART_LCR + Async_Base] := Port[UART_LCR + Async_Base] and $7F; 
  644.  
  645.   { read the Line Status Register to reset any errors it indicates } 
  646.  
  647.       i := Port[UART_LSR + Async_Base];
  648.  
  649.   { read the Receiver Buffer Register in case it contains a character }
  650.  
  651.       i := Port[UART_RBR + Async_Base]; 
  652.  
  653.  
  654.  
  655.   { enable the irq on the 8259 controller } 
  656.  
  657.       i := Port[I8088_IMR];  { get the interrupt mask register } 
  658.  
  659.       m := (1 shl Async_Irq) xor $00FF;
  660.  
  661.       Port[I8088_IMR] := i and m; 
  662.  
  663.  
  664.  
  665.   { enable the data ready interrupt on the 8250 } 
  666.  
  667.       Port[UART_IER + Async_Base] := $01; { enable data ready interrupt } 
  668.  
  669.  
  670.  
  671.   { enable OUT2 on 8250 } 
  672.  
  673.       i := Port[UART_MCR + Async_Base]; 
  674.  
  675.       Port[UART_MCR + Async_Base] := i or $08; 
  676.  
  677.  
  678.  
  679.       Inline($FB); { enable interrupts }
  680.  
  681.       Async_Open_Flag := TRUE;  { bug fix by Scott Herr }
  682.  
  683.       Async_Open := TRUE 
  684.  
  685.     end 
  686.  
  687. end; { Async_Open } 
  688.  
  689.  
  690.  
  691. function Async_Buffer_Check(var C : Char) : Boolean; 
  692.  
  693. { see if a character has been received; return it if yes }
  694.  
  695. begin
  696.  
  697.   if Async_Buffer_Head = Async_Buffer_Tail then 
  698.  
  699.     Async_Buffer_Check := FALSE 
  700.  
  701.   else 
  702.  
  703.     begin 
  704.  
  705.       C := Async_Buffer[Async_Buffer_Tail];
  706.  
  707.       Async_Buffer_Tail := Async_Buffer_Tail + 1; 
  708.  
  709.       if Async_Buffer_Tail > Async_Buffer_Max then 
  710.  
  711.         Async_Buffer_Tail := 0; 
  712.  
  713.       Async_Buffer_Used := Async_Buffer_Used - 1; 
  714.  
  715.       Async_Buffer_Check := TRUE 
  716.  
  717.     end 
  718.  
  719. end; { Async_Buffer_Check } 
  720.  
  721.  
  722.  
  723. procedure Async_Send(C : Char); 
  724.  
  725. { transmit a character } 
  726.  
  727. var 
  728.  
  729.   i, m, counter : Integer; 
  730.  
  731. begin 
  732.  
  733.   Port[UART_MCR + Async_Base] := $0B; { turn on OUT2, DTR, and RTS } 
  734.  
  735.  
  736.  
  737.   { wait for CTS } 
  738.  
  739.   counter := MaxInt;
  740.  
  741.   while (counter <> 0) and ((Port[UART_MSR + Async_Base] and $10) = 0) do
  742.  
  743.     counter := counter - 1; 
  744.  
  745.  
  746.  
  747.   { wait for Transmit Hold Register Empty (THRE) } 
  748.  
  749.   if counter <> 0 then counter := MaxInt;
  750.  
  751.   while (counter <> 0) and ((Port[UART_LSR + Async_Base] and $20) = 0) do
  752.  
  753.     counter := counter - 1; 
  754.  
  755.  
  756.  
  757.   if counter <> 0 then 
  758.  
  759.     begin 
  760.  
  761.       { send the character } 
  762.  
  763.       Inline($FA); { disable interrupts } 
  764.  
  765.       Port[UART_THR + Async_Base] := Ord(C); 
  766.  
  767.       Inline($FB) { enable interrupts } 
  768.  
  769.     end 
  770.  
  771.   else 
  772.  
  773.     writeln('<<<TIMEOUT>>>'); 
  774.  
  775.  
  776.  
  777. end; { Async_Send } 
  778.  
  779.  
  780.  
  781. procedure Async_Send_String(S : LStr); 
  782.  
  783. { transmit a string } 
  784.  
  785. var
  786.  
  787.   i : Integer;
  788.  
  789. begin 
  790.  
  791.   for i := 1 to length(S) do
  792.  
  793.     Async_Send(S[i])
  794.  
  795. end; { Async_Send_String }
  796.  
  797. Capture buffer closed.
  798.  
  799.  
  800.  
  801.